const fs = require('fs');
const path = require('path');
const sharp = require('sharp');
const { promisify } = require('util');

// 全局变量：目标压缩路径（外部调用时赋值）、根路径（用于临时目录）
pathStr = 'C:/Users/ASUS/Desktop/meiriwalk'; // 目标压缩路径（外部需设置，如：pathStr = '/xxx/images'）
rootPathStr = __dirname; // 根路径（默认脚本所在目录，可外部修改）

// 使用Node.js内置的fs.promises
const fsPromises = fs.promises;

// 转换为Promise API
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
const mkdirSync = fs.mkdirSync;
const copyFileSync = fs.copyFileSync;
const unlinkSync = fs.unlinkSync;
const statSync = fs.statSync;
const existsSync = fs.existsSync;
const readdirSync = fs.readdirSync;
const rmdirSync = fs.rmdirSync;

// 支持的图片格式
const SUPPORTED_FORMATS = ['.png', '.jpg', '.jpeg', '.webp', '.gif', '.tiff'];

/**
 * 检查文件是否为支持的图片类型
 * @param {string} filePath - 文件路径
 * @returns {boolean} 是否为支持的图片
 */
function isSupportedImage(filePath) {
    const ext = path.extname(filePath).toLowerCase();
    return SUPPORTED_FORMATS.includes(ext);
}

/**
 * 同步删除文件夹（递归）
 * @param {string} dirPath - 文件夹路径
 */
function deleteFolderSync(dirPath) {
    if (existsSync(dirPath)) {
        readdirSync(dirPath).forEach((file) => {
            const curPath = path.join(dirPath, file);
            if (statSync(curPath).isDirectory()) {
                deleteFolderSync(curPath);
            } else {
                unlinkSync(curPath);
            }
        });
        rmdirSync(dirPath);
    }
}

/**
 * 根据图片格式设置最佳压缩参数并进行压缩
 * @param {string} inputPath - 输入图片路径
 * @param {string} outputPath - 输出图片路径（临时文件）
 * @returns {number} 节省的百分比（负数表示变大，0表示无变化）
 */
async function compressImage(inputPath, outputPath) {
    try {
        const ext = path.extname(inputPath).toLowerCase();
        const image = sharp(inputPath);
        const uniQuality = 80;

        // 不同格式的最佳压缩参数
        switch (ext) {
            case '.png':
                await image.png({
                    quality: uniQuality,
                    compressionLevel: 6,
                    force: false
                }).toFile(outputPath);
                break;
            case '.jpg':
            case '.jpeg':
                await image.jpeg({
                    quality: uniQuality,
                    mozjpeg: true,
                    force: false
                }).toFile(outputPath);
                break;
            case '.webp':
                await image.webp({
                    quality: uniQuality,
                    force: false
                }).toFile(outputPath);
                break;
            case '.gif':
                await image.gif({
                    quality: uniQuality,
                    force: false
                }).toFile(outputPath);
                break;
            case '.tiff':
                await image.tiff({
                    quality: uniQuality,
                    force: false
                }).toFile(outputPath);
                break;
            default:
                throw new Error(`不支持的图片格式: ${ext}`);
        }

        // 计算压缩前后大小
        const originalSize = (await stat(inputPath)).size;
        const compressedSize = (await stat(outputPath)).size;
        return ((originalSize - compressedSize) / originalSize * 100).toFixed(2);
    } catch (error) {
        console.error(`压缩失败: ${path.basename(inputPath)} - ${error.message}`);
        return -100; // 异常时返回极端负值，视为压缩失败
    }
}

/**
 * 递归处理目录下的图片（原地替换逻辑）
 * @param {string} targetDir - 目标处理目录
 * @param {string} tempDir - 临时目录
 */
async function processDirectoryInPlace(targetDir, tempDir) {
    try {
        // 确保临时目录存在（按原目录结构创建临时子目录）
        mkdirSync(tempDir, { recursive: true });

        const entries = readdirSync(targetDir, { withFileTypes: true });

        for (const entry of entries) {
            const targetPath = path.join(targetDir, entry.name);
            const tempSubDir = path.join(tempDir, entry.name); // 临时目录同步原目录结构

            if (entry.isDirectory()) {
                // 递归处理子目录
                await processDirectoryInPlace(targetPath, tempSubDir);
            } else if (entry.isFile() && isSupportedImage(targetPath)) {
                console.log(`开始处理图片: ${path.relative(rootPathStr, targetPath)}`);

                // 临时文件路径（避免覆盖原文件）
                const fileName = path.basename(targetPath);
                const tempCompressPath = path.join(tempDir, `temp_${fileName}`);

                // 循环压缩直到无法优化
                let currentTempPath = path.join(tempDir, `origin_${fileName}`);
                copyFileSync(targetPath, currentTempPath); // 复制原图到临时文件
                let hasImprovement = true;
                let round = 1;
                let finalSavings = 0;

                while (hasImprovement) {
                    console.log(`  第${round}轮压缩...`);
                    const savings = await compressImage(currentTempPath, tempCompressPath);
                    const savingsNum = parseFloat(savings);

                    if (savingsNum > 0) {
                        // 有优化：更新临时文件，准备下一轮
                        if (existsSync(currentTempPath)) unlinkSync(currentTempPath);
                        copyFileSync(tempCompressPath, currentTempPath);
                        if (existsSync(tempCompressPath)) unlinkSync(tempCompressPath);
                        finalSavings = savingsNum;
                        round++;
                    } else {
                        // 无优化或压缩失败：结束循环
                        hasImprovement = false;
                        if (existsSync(tempCompressPath)) unlinkSync(tempCompressPath);
                    }
                }

                // 最终判断：只有压缩后体积更小，才替换原图
                if (finalSavings > 0) {
                    // 替换原图（先删除再复制，避免权限问题）
                    if (existsSync(targetPath)) unlinkSync(targetPath);
                    copyFileSync(currentTempPath, targetPath);
                    console.log(`  压缩成功：替换原图（节省 ${finalSavings}%）- ${path.basename(targetPath)}`);
                } else {
                    console.log(`  无优化：不替换原图 - ${path.basename(targetPath)}`);
                }

                // 清理当前图片的临时文件
                if (existsSync(currentTempPath)) unlinkSync(currentTempPath);
            }
        }
    } catch (error) {
        console.error(`处理目录出错: ${path.relative(rootPathStr, targetDir)} - ${error.message}`);
    }
}

/**
 * 核心工具函数：执行原地图片压缩
 */
async function executeImageCompressionInPlace() {
    // 校验目标路径
    if (!pathStr || !existsSync(pathStr) || !statSync(pathStr).isDirectory()) {
        console.error('错误：目标路径无效或未设置（请设置 global.pathStr）');
        return;
    }

    const targetDir = path.resolve(pathStr);
    const tempDir = path.join(rootPathStr, 'temp_image_compress'); // 根路径下的临时目录

    console.log('------------------------------');
    console.log('开始执行原地图片压缩');
    console.log(`目标路径: ${targetDir}`);
    console.log(`临时目录: ${tempDir}`);
    console.log('规则：压缩后体积更小则替换原图，否则不替换');
    console.log('------------------------------');

    try {
        // 执行核心处理
        await processDirectoryInPlace(targetDir, tempDir);
        console.log('------------------------------');
        console.log('所有图片处理完成！');
        console.log('已保留优化后的图片，无优化的图片未做修改');
    } finally {
        // 强制清理临时目录（无论成功失败）
        try {
            if (existsSync(tempDir)) {
                deleteFolderSync(tempDir);
                console.log('临时目录已清理：', tempDir);
            }
        } catch (err) {
            console.error('清理临时目录时出错:', err.message);
        }
    }
}

// 暴露核心工具函数（外部可直接调用）
// module.exports = {
//     executeImageCompressionInPlace
// }

executeImageCompressionInPlace()